﻿/*

  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at 
  
           http://www.mozilla.org/MPL/ 
  
  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the License. 
  
  The Original Code is LunAS Library.
  
  The Initial Developer of the Original Code is
  ALCARAZ Marc (aka eKameleon)  <ekameleon@gmail.com>.
  Portions created by the Initial Developer are Copyright (C) 2004-2012
  the Initial Developer. All Rights Reserved.
  
  Contributor(s) :
  
  Alternatively, the contents of this file may be used under the terms of
  either the GNU General Public License Version 2 or later (the "GPL"), or
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  in which case the provisions of the GPL or the LGPL are applicable instead
  of those above. If you wish to allow use of your version of this file only
  under the terms of either the GPL or the LGPL, and not to allow others to
  use your version of this file under the terms of the MPL, indicate your
  decision by deleting the provisions above and replace them with the notice
  and other provisions required by the LGPL or the GPL. If you do not delete
  the provisions above, a recipient may use your version of this file under
  the terms of any one of the MPL, the GPL or the LGPL.
  
*/
package lunas.containers 
{
    import graphics.Direction;
    import graphics.FillStyle;
    import graphics.drawing.IPen;
    import graphics.drawing.RectanglePen;
    import graphics.geom.EdgeMetrics;
    import graphics.layouts.GridLayout;
    import graphics.layouts.Layout;
    
    import system.hack;
    
    import flash.display.Sprite;
    import flash.geom.Rectangle;
    
    /**
     * This container use a matrix layout pattern.
     * <p><b>Example :</b></p>
     * <pre class="prettyprint">
     * import flash.display.StageScaleMode ;
     * import flash.filters.DropShadowFilter ;
     * 
     * import lunas.containers.MatrixContainer ;
     * 
     * import graphics.Direction;
     * import graphics.FillStyle ;
     * import graphics.drawing.RectanglePen ;
     * 
     * stage.scaleMode = StageScaleMode.NO_SCALE ;
     * 
     * var container:MatrixContainer = new MatrixContainer() ;
     * container.x = 25 ;
     * container.y = 25 ;
     * container.space = 10 ;
     * 
     * container.columns   = 10 ;
     * container.lines     = 10 ;
     * container.direction = Direction.HORIZONTAL ;
     * 
     * addChild( container ) ;
     * 
     * var createNewSquare:Function = function()
     * {
     *     var square:Shape            = new Shape() ;
     *     var shadow:DropShadowFilter = new DropShadowFilter( 2, 90, 0x000000, 0.7, 10, 10, 1, 2) ;
     *     var pen:RectanglePen        = new RectanglePen( square ) ;
     *     
     *     pen.fill = new FillStyle( Math.random() &#42; 0xFFFFFF ) ;
     *     pen.draw(0,0,10,10) ;
     *     
     *     square.filters = [ shadow ] ;
     *     
     *     container.addChild( square  )  ;
     * }
     * 
     * for (var i:int = 0 ; i &lt; 12 ; i++ )
     * {
     *     createNewSquare() ;
     * }
     * 
     * var keyDown:Function = function( e:KeyboardEvent ):void
     * {
     *     var code:uint = e.keyCode ;
     *     switch( code )
     *     {
     *         case Keyboard.UP :
     *         {
     *             container.clear() ;
     *             break ;
     *         }
     *         case Keyboard.SPACE :
     *         {
     *              container.direction = container.direction == Direction.HORIZONTAL ? Direction.VERTICAL : Direction.HORIZONTAL ;
     *              break ;
     *         }
     *         default :
     *         {
     *             createNewSquare() ;
     *         }
     *     }
     * }
     * 
     * stage.addEventListener( KeyboardEvent.KEY_DOWN , keyDown ) ;
     * </pre>
     */
    public class GridContainer extends Container 
    {
        use namespace hack ;
        
        /**
         * Creates a new GridContainer instance.
         * @param init An object that contains properties with which to populate the newly instance. If init is not an object, it is ignored.
         */
        public function GridContainer( init:Object = null  )
        {
            lock() ;
            
            ////////
            
            super() ;
            
            ////////
            
            _background         = new Sprite() ;
            _container          = new Sprite() ;
            _mask               = new Sprite() ;
            _area               = new Sprite() ;
            
            ////////
            
            _background.buttonMode   = false ;
            _background.mouseEnabled = false ;
            
            _container.buttonMode    = false ;
            _container.mouseEnabled  = false ;
            
            _area.buttonMode         = false ; 
            _area.mouseEnabled       = false ;
            
            _mask.buttonMode         = false ; 
            _mask.mouseEnabled       = false ;
            
            ////////
            
            _areaPen       = new RectanglePen( _area ) ;
            _backgroundPen = new RectanglePen( _background ) ;
            _maskPen       = new RectanglePen( _mask ) ;
            
            _areaPen.fill       = new FillStyle( 0 , 0 ) ;
            _backgroundPen.fill = new FillStyle( 0 , 0 ) ;
            _maskPen.fill       = new FillStyle( 0 , 0 ) ;
            // _maskPen.fill       = new FillStyle( 0xFF0000 , 0.2 ) ; // Test only
            
            ////////
            
            _direction = Direction.VERTICAL ;
            
            addChild( _background ) ;
            addChild( _container ) ;
            addChild( _mask ) ;
            addChild( _area ) ;
            
            ////////
            
            _layout = new GridLayout() ;
            
            _layout.renderer.connect( renderLayout , 9999 ) ;
            _layout.updater.connect( updateLayout , 9999 ) ;
            
            ////////
            
            scope = _container ;
            
            unlock() ;
            
            ////////
            
            initialize( init ) ;
        }
        
        /**
         * Returns the area reference of this component.
         */
        public function get area():Sprite 
        {
            return _area ;
        }
        
        /**
         * Indicates the area Pen reference of this component.
         */
        public function get areaPen():IPen 
        {
            return _areaPen ;
        }
        
        /**
         * Indicates the background reference of this component.
         */
        public function get background():Sprite 
        {
            return _background ;
        }
        
        /**
         * Indicates the background Pen reference of this component.
         */
        public function get backgroundPen():IPen 
        {
            return _backgroundPen ;
        }
        
        /**
         * Determinates the number of childs in this container. If this value is -1 no mask effect is apply over the list container, all the childs are visible.
         */
        public function get childCount():int 
        {
            return _layout ? (_layout as GridLayout).childCount : -1 ;
        }
        
        /**
         * Sets the number of childs visible in this container.
         */
        public function set childCount( value:int ):void 
        {
            if( _layout )
            {
                (_layout as GridLayout).childCount = value ;
            }
            update() ;
        }
        
        /**
         * Determinates the number of columns in the matrix layout if the direction of this container is Direction.HORIZONTAL.
         * @see graphics.Direction
         */
        public function get columns():int 
        {
            return (_layout as GridLayout).columns ;
        }
        
        /**
         * @private
         */
        public function set columns( value:int ):void 
        {
            (_layout as GridLayout).columns = value ;
            update() ;
        }
        
        /**
         * Indicates the direction value of the background when the display is in this "full" mode (default value is null).
         * @see graphics.Direction
         */
        public override function get direction():String
        {
            return (_layout as GridLayout).direction ;
        }
        
        /**
         * @private
         */
        public override function set direction( value:String ):void
        {
            (_layout as GridLayout).direction = value ;
            update() ;
        }
        
        /**
         * Number of pixels between children in the horizontal direction. 
         * The default value depends on the component class; if not overriden for the class, the default value is 0.
         */
        public function get horizontalGap():Number
        {
            return (_layout as GridLayout).horizontalGap ;
        }
        
        /**
         * @private
         */
        public function set horizontalGap( value:Number ):void
        {
            (_layout as GridLayout).horizontalGap = value ;
            update() ;
        }
        
        /**
         * @private
         */
        public override function set layout( layout:Layout ):void
        {
            super.layout = layout is GridLayout ? layout : new GridLayout( _scope ) ;
        }
        
        /**
         * Determinates the number of lines in the matrix layout if the direction of this container is Direction.VERTICAL.
         * @see graphics.Direction
         */
        public function get lines():int 
        {
            return (_layout as GridLayout).lines ;
        }
        
        /**
         * @private
         */
        public function set lines( value:int ):void 
        {
            (_layout as GridLayout).lines = value ;
            update() ;
        }
        
        /**
         * Use the mask protection.
         */
        public function lockMask():void
        {
            _lockMask = true ;
        }
        
        /**
         * Indicates if the mask is active or not over this container.
         */
        public function get maskIsActive():Boolean 
        {    
            return _maskIsActive ;
        }
        
        /**
          * @private
          */
        public function set maskIsActive( b:Boolean ):void 
        {
            _maskIsActive = b ;
            update() ;
        }
        
        /**
         * Determinates the mask reference of this container.
         */
        public function get maskView():Sprite 
        {    
            return _mask ;
        }
        
        /**
         * Specifies the thickness, in pixels, of the four edge regions around the box layout.
         */
        public function get padding():EdgeMetrics
        {
            return (_layout as GridLayout).padding ;
        }
        
        /**
         * @private
         */
        public function set padding( em:EdgeMetrics ):void
        {
            (_layout as GridLayout).padding = em ;
            update() ;
        }
        
        /**
         * Unlock the mask protect.
         */
        public function unlockMask():void
        {
            _lockMask = false;
        }
        
        /**
         * Indicates if this container use a scrollRect reference to mask the content.
         */
        public function get useScrollRect():Boolean
        {
            return _useScrollRect ;
        }
        
        /**
         * @private
         */
        public function set useScrollRect( b:Boolean ):void
        {
            _useScrollRect = b ;
            update() ;
        }
        
        /**
         * Number of pixels between children in the vertical direction. 
         * The default value depends on the component class; if not overriden for the class, the default value is 0.
         */
        public function get verticalGap():Number
        {
            return (_layout as GridLayout).verticalGap ;
        }
        
        /**
         * @private
         */
        public function set verticalGap( value:Number ):void
        {
            (_layout as GridLayout).verticalGap = value ;
            update() ;
        }
        
        /**
         * This area sprite defines a hide background display back of the display.
         */
        protected var _area:Sprite ;
        
        /**
         * The pen of the area IPen object.
         */
        protected var _areaPen:RectanglePen ;
        
        /**
         * This Background reference defines a background display.
         */
        protected var _background:Sprite ;
        
        /**
         * The pen of the background Pen object.
         */
        protected var _backgroundPen:RectanglePen ;
        
        /**
         * This CoreSprite reference defines a container display.
         */
        protected var _container:Sprite ;
        
        /**
         * The mask display of this containerr.
         */
        protected var _mask:Sprite ;
        
        /**
         * The pen of the mask IPen object.
         */
        protected var _maskPen:RectanglePen ;
        
        /**
         * Invoked when the container layout change.
         */
        protected override function updateLayout( layout:Layout = null ):void 
        {
            var bounds:Rectangle = layout.bounds ;
            
            _areaPen.draw(bounds.x,bounds.y,bounds.width,bounds.height) ;
            _backgroundPen.draw(bounds.x,bounds.y,bounds.width,bounds.height) ;
            
            scrollRect = null ;
            mask       = null ;
            
            _mask.graphics.clear() ;
            
            if( _useScrollRect )
            {
                scrollRect = bounds ; 
            }
            else if ( maskIsActive && !_lockMask ) 
            {
                _maskPen.draw( bounds.x, bounds.y, bounds.width, bounds.height ) ;
                
                mask = _mask ; // remove this line to test the mask only
                
                if ( useScrollRect )
                {
                    scrollRect = bounds ;
                }
            }
        }
        
        /**
         * @private
         */
        private var _lockMask:Boolean ;
        
        /**
         * @private
         */
        private var _maskIsActive:Boolean ;
        
        /**
         * @private
         */
        private var _useScrollRect:Boolean = true ;
    }
}

